<template>
  <div class="chat-container" :class="currentTheme">
    <!-- 连接状态提示 -->
    <div v-if="!isConnected" class="connection-status" :class="{
      'reconnecting': reconnectAttempts > 0
    }">
      <svg class="loading-circle" viewBox="0 0 24 24">
        <path fill="currentColor"
              d="M12 4V2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10h-2c0 4.41-3.59 8-8 8s-8-3.59-8-8s3.59-8 8-8z"/>
      </svg>
      <span>
        {{
          reconnectAttempts > 0
              ? `正在尝试第 ${reconnectAttempts} 次重新连接...`
              : '正在连接到服务器...'
        }}
      </span>
    </div>

    <!-- 聊天消息列表 -->
    <ChatMessages
        ref="chatMessagesRef"
        :messages="messages"
        :maxOutputTokens="maxOutputTokens"
        @regenerate="regenerateResponse"
        @scroll="handleScroll"
    />

    <!-- 滚动按钮 -->
    <Transition name="fade">
      <button
          v-show="showScrollButton"
          class="scroll-button"
          @click="scrollToBottom"
          title="滚动到底部"
      >
        <svg viewBox="0 0 24 24" class="scroll-icon">
          <path fill="currentColor" d="M16.59 8.59L12 13.17L7.41 8.59L6 10l6 6l6-6l-1.41-1.41z"/>
        </svg>
        <span class="scroll-tooltip">新消息</span>
      </button>
    </Transition>

    <!-- 输入框 -->
    <ChatInput
        :loading="loading"
        :disabled="loading || !isConnected"
        :isConnected="isConnected"
        @send="handleSend"
        @stop="stopGeneration"
    />

    <!-- 历史对话 -->
    <ChatHistory
        :dialogues="dialogueHistory"
        @load="loadDialogue"
        @delete="deleteDialogue"
    />

  </div>
</template>

<script setup>
import {nextTick, onMounted, onUnmounted, ref} from 'vue'
import {encode} from 'gpt-tokenizer'
import ChatMessages from './components/ChatMessages.vue'
import ChatInput from './components/ChatInput.vue'
import ChatHistory from './components/ChatHistory.vue'
import config from "@/config/index.js";

const ws = ref(null)
const messages = ref([
  {role: 'assistant', content: '你好！我是AI助手,有什么可以帮你的吗?'}
])
const loading = ref(false)
const isConnected = ref(false)
const reconnectAttempts = ref(0)
const maxReconnectAttempts = 3
const reconnectTimer = ref(null)
const showScrollButton = ref(false)
const chatMessagesRef = ref(null)
const maxOutputTokens = 8000
const currentDialogue = ref([])
const reconnectIntervals = [5000, 30000, 60000]

// 历史对话列表
const dialogueHistory = ref([])

// 主题相关
const currentTheme = ref('default')

const getReconnectDelay = (attempt) => {
  return reconnectIntervals[Math.min(attempt, reconnectIntervals.length - 1)]
}

const clearReconnectTimer = () => {
  if (reconnectTimer.value) {
    clearTimeout(reconnectTimer.value)
    reconnectTimer.value = null
  }
}

const calculateTokens = (text) => {
  if (!text) return 0
  return encode(text).length
}

const handleSend = (message) => {
  const userMessage = {
    role: 'user',
    content: message,
    timestamp: Date.now()
  }

  messages.value.push(userMessage)
  currentDialogue.value.push(userMessage)

  nextTick(() => {
    chatMessagesRef.value?.scrollToBottom()
  })

  loading.value = true

  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    const msg = {
      type: 'prompt',
      message: message
    }
    ws.value.send(JSON.stringify(msg))
  }
}

const handleScroll = (shouldShow) => {
  showScrollButton.value = shouldShow
}

const scrollToBottom = () => {
  chatMessagesRef.value?.scrollToBottom()
  showScrollButton.value = false
}

const handleWebSocketMessage = (event) => {
  if (!loading.value) return

  let message = ''
  const msg = JSON.parse(event.data)

  if (msg.messageType === 'content' || msg.messageType === 'reasoning') {
    message = msg.content

    const lastMessage = messages.value[messages.value.length - 1]

    if (lastMessage && lastMessage.role === 'assistant') {
      lastMessage.content += message
      lastMessage.tokens = calculateTokens(lastMessage.content)
      lastMessage.responseTime = Date.now() - lastMessage.timestamp
      if (currentDialogue.value.length > 0) {
        currentDialogue.value[currentDialogue.value.length - 1].content = lastMessage.content
        currentDialogue.value[currentDialogue.value.length - 1].tokens = lastMessage.tokens
        currentDialogue.value[currentDialogue.value.length - 1].responseTime = lastMessage.responseTime
      }
    } else {
      const newMessage = {
        role: 'assistant',
        content: message,
        timestamp: Date.now(),
        tokens: calculateTokens(message),
        responseTime: 0
      }
      messages.value.push(newMessage)
      currentDialogue.value.push(newMessage)
    }

    if (!showScrollButton.value) {
      nextTick(() => {
        chatMessagesRef.value?.scrollToBottom()
      })
    }
  } else if (msg.messageType === 'error') {
    console.error('服务器错误:', msg.content)
    loading.value = false
  } else if (msg.messageType === 'over') {
    const lastMessage = messages.value[messages.value.length - 1]
    if (lastMessage && lastMessage.role === 'assistant') {
      lastMessage.tokens = calculateTokens(lastMessage.content)
      lastMessage.responseTime = Date.now() - lastMessage.timestamp
      if (currentDialogue.value.length > 0) {
        currentDialogue.value[currentDialogue.value.length - 1].tokens = lastMessage.tokens
        currentDialogue.value[currentDialogue.value.length - 1].responseTime = lastMessage.responseTime
      }
    }
    sendDialogueSummary()
    loading.value = false
  }
}

const regenerateResponse = (index) => {
  if (loading.value) return

  const previousMessages = messages.value.slice(0, index)
  const lastUserMessage = previousMessages.findLast(m => m.role === 'user')

  if (lastUserMessage) {
    messages.value = messages.value.slice(0, index)
    loading.value = true
    if (ws.value && ws.value.readyState === WebSocket.OPEN) {
      const msg = {
        type: 'prompt',
        message: lastUserMessage.content
      }
      ws.value.send(JSON.stringify(msg))
    }
  }
}

const sendDialogueSummary = () => {
  if (!currentDialogue.value.length) return

  const summary = {
    type: 'dialogue_summary',
    messages: currentDialogue.value.map(msg => ({
      role: msg.role,
      content: msg.content,
      timestamp: msg.timestamp,
      tokens: msg.tokens || calculateTokens(msg.content)
    })),
    totalMessages: currentDialogue.value.length,
    totalTokens: currentDialogue.value.reduce((sum, msg) => sum + (msg.tokens || 0), 0),
    startTime: currentDialogue.value[0].timestamp,
    endTime: Date.now()
  }

  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.send(JSON.stringify(summary))
  }

  // 添加到历史对话
  dialogueHistory.value.unshift({
    ...summary,
    title: currentDialogue.value[0].content
  })

  currentDialogue.value = []
}

const connectWebSocket = () => {
  if (ws.value && (ws.value.readyState === WebSocket.CONNECTING ||
      ws.value.readyState === WebSocket.OPEN)) {
    return
  }

  if (ws.value) {
    ws.value.close()
    ws.value = null
  }

  try {
    let url = config.REMOTE_URL;
    if (url.startsWith('http')){
      url = url.replace('http', 'ws');
    }else{
      url = url.replace('https', 'wss');
    }

    ws.value = new WebSocket(`${url}/websocket`)

    ws.value.onopen = () => {
      isConnected.value = true
      reconnectAttempts.value = 0
      clearReconnectTimer()
    }

    ws.value.onclose = (event) => {
      isConnected.value = false

      if (!loading.value && reconnectAttempts.value < maxReconnectAttempts) {
        const delay = getReconnectDelay(reconnectAttempts.value)
        clearReconnectTimer()
        reconnectTimer.value = setTimeout(() => {
          reconnectAttempts.value++
          connectWebSocket()
        }, delay)
      }
    }

    ws.value.onerror = () => {
      isConnected.value = false
    }

    ws.value.onmessage = handleWebSocketMessage
  } catch (error) {
    console.error('WebSocket连接创建失败:', error)
    isConnected.value = false
  }
}

// 加载历史对话
const loadDialogue = (dialogue) => {
  messages.value = dialogue.messages.map(msg => ({
    ...msg,
    timestamp: Date.now()
  }))
}

// 删除历史对话
const deleteDialogue = (index) => {
  dialogueHistory.value.splice(index, 1)
  // 可以在这里添加持久化存储的逻辑
}

// 终止生成
const stopGeneration = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    const msg = {
      type: 'stop'
    }
    ws.value.send(JSON.stringify(msg))

    // 发送当前对话汇总
    sendDialogueSummary()
    loading.value = false
  }
}

const changeTheme = (themeId) => {
  currentTheme.value = themeId
}

onMounted(() => {
  connectWebSocket()
})

onUnmounted(() => {
  clearReconnectTimer()
  if (ws.value) {
    ws.value.close()
    ws.value = null
  }

  if (currentDialogue.value.length > 0) {
    sendDialogueSummary()
  }
})
</script>


<style scoped>
.chat-container {
  height: calc(100vh - 80px);
  display: flex;
  flex-direction: column;
  border-radius: 8px;
  position: relative;
  overflow: hidden;
}

.connection-status {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  padding: 12px;
  background-color: #f3f4f6;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: #6b7280;
  font-size: 14px;
  z-index: 10;
  transition: all 0.3s ease;
}

.connection-status.reconnecting {
  background-color: #fff7ed;
  color: #9a3412;
}

.loading-circle {
  width: 20px;
  height: 20px;
  animation: spin 1s linear infinite;
}

.scroll-button {
  position: fixed;
  right: 24px;
  bottom: 120px;
  width: 40px;
  height: 40px;
  border-radius: 20px;
  background-color: #ffffff;
  border: 1px solid #e2e8f0;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease;
  z-index: 100;
}

.scroll-button:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  background-color: #f8fafc;
}

.scroll-button:active {
  transform: translateY(0);
}

.scroll-icon {
  width: 24px;
  height: 24px;
  color: #64748b;
  transition: color 0.3s ease;
}

.scroll-button:hover .scroll-icon {
  color: #0ea5e9;
}

.scroll-tooltip {
  position: absolute;
  right: 48px;
  padding: 4px 8px;
  background-color: #1e293b;
  color: white;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  opacity: 0;
  transform: translateX(10px);
  transition: all 0.3s ease;
  pointer-events: none;
}

.scroll-button:hover .scroll-tooltip {
  opacity: 1;
  transform: translateX(0);
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: translateY(20px);
}

@media (prefers-color-scheme: dark) {
  .chat-container {
    background-color: #1a1a1a;
  }
}
</style>
